package com.nulldev.util.osAPI.hardware.cpu;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Pattern;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.io.file.FileUtil;
import com.nulldev.util.osAPI.OS;
import com.nulldev.util.processAPI.Processes;

public class CPUs {
	public static CPU parse() {
		if (OS.isWindows()) {
			final String CPU_INFO = System.getenv("PROCESSOR_IDENTIFIER");
			if (CPU_INFO == null) {
				return new CPU(Vendor.UNKNOWN, "Unknown Brand, Unknown CPU");
			}
			if (CPU_INFO.contains("AuthenticAMD")) {
				return new CPU(Vendor.AMD, CPU_INFO);
			} else if (CPU_INFO.contains("GenuineIntel")) {
				return new CPU(Vendor.INTEL, CPU_INFO);
			} else if (CPU_INFO.contains("VIA VIA VIA ")) {
				return new CPU(Vendor.VIA, CPU_INFO);
			} else if (CPU_INFO.contains("bhyve bhyve ") || CPU_INFO.contains("KVMKVMKVM") || CPU_INFO.contains("Microsoft Hv")
					|| CPU_INFO.contains(" lrpepyh vr") || CPU_INFO.contains("VMwareVMware") || CPU_INFO.contains("XenVMMXenVMM")) {
				return new CPU(Vendor.VIRTUAL_MACHINE, CPU_INFO);
			}
			return new CPU(Vendor.UNKNOWN, "Unknown Brand, Unknown CPU");
		} else if (OS.isLinux()) {
			try {
				final String filtered = test_linux_parse(Processes.execCmd("cat /proc/cpuinfo"));
				final String[] data = byLineSepeartorAI(filtered);
				final String[] raw = StringsUtil.byLineSepeartor(filtered);
				Vendor vendor = Vendor.UNKNOWN;
				String cpu_name = "Unknown Brand, Unknown CPU";
				for (final String entry : data) {
					final String[] val = entry.split(":");
					if (val[0].equals("vendor_id")) {
						final String CPU_INFO = val[1].substring(1);
						if (CPU_INFO.contains("AuthenticAMD")) {
							vendor = Vendor.AMD;
						} else if (CPU_INFO.contains("GenuineIntel")) {
							vendor = Vendor.INTEL;
						} else if (CPU_INFO.contains("VIA VIA VIA ")) {
							vendor = Vendor.VIA;
						} else if (CPU_INFO.contains("bhyve bhyve ") || CPU_INFO.contains("KVMKVMKVM") || CPU_INFO.contains("Microsoft Hv")
								|| CPU_INFO.contains(" lrpepyh vr") || CPU_INFO.contains("VMwareVMware") || CPU_INFO.contains("XenVMMXenVMM")) {
							vendor = Vendor.VIRTUAL_MACHINE;
						}
					} else if (val[0].equals("model name")) {
						cpu_name = val[1].substring(1).replaceAll("_NL_", "");
					}
				}
				final CPU cpu = new CPU(vendor, cpu_name);
				cpu.override_data(raw);
				return cpu;
			} catch (IOException e) {
				JVM.errorln(e);
			}
		}
		return new CPU(Vendor.UNKNOWN, "Unknown Brand, Unknown CPU");
	}

	public static String getArch() {
		return System.getProperty("os.arch");
	}

	public static String[] getBackdoors() {
		final ArrayList<String> output = new ArrayList<String>();
		final CPU cpu = parse();
		if (OS.isLinux()) {
			final File imeIF = FileUtil.safeCreate("/dev/mei0");
			if (imeIF.exists()) {
				output.add("Intel.IME");
			}
		}
		if (cpu.getVendor().equals(Vendor.AMD) || cpu.getVendor().equals(Vendor.AMD_ALT)) {
			if (cpu.getBrand().equals(Brand.Zen) || cpu.getBrand().equals(Brand.A_Series) || cpu.getBrand().equals(Brand.Jaguar)
					|| cpu.getBrand().equals(Brand.A_Series_G1)) {
				output.add("AMD.PSP");
			}
		}
		return ArrayUtils.arrayListToArray(output);
	}

	private static String test_linux_parse(final String data) {
		final StringBuilder out = new StringBuilder();
		for (final char x : data.toCharArray()) {
			// x != '\u0073' &&
			if (x != '\u0009') {
				out.append(x);
			}
		}
		return out.toString();
	}

	private static String[] byLineSepeartorAI(String filtered) {
		final ArrayList<String> out = new ArrayList<String>();
		for (final String i : filtered.split(Pattern.quote(JVM.lineSeperator()))) {
			out.add(i + "_NL_");
		}
		return ArrayUtils.arrayListToArray(out);
	}

	public static String[] getBugs() {
		if (getArch().equals("amd64") || getArch().equals("x86")) {
			if (OS.isLinux()) {
				String filtered = "";
				try {
					filtered = test_linux_parse(Processes.execCmd("cat /proc/cpuinfo"));
				} catch (IOException e) {
				}
//				final String[] data = byLineSepeartorAI(filtered);
				final String[] raw = StringsUtil.byLineSepeartor(filtered);
				final ArrayList<String> bugs = new ArrayList<String>();
				for (final String s : raw) {
					final String[] sp = s.split(": ");
					if (StringsUtil.isEqualCM(sp, 0, "bugs")) {
						final String[] bs = sp[1].split(" ");
						for (final String b : bs) {
							bugs.add(b);
						}
						break;
					}
				}
				return ArrayUtils.arrayListToArray(bugs);
			}
		}
		return new String[0];
	}
}
